<?php
/**
 * Валидатор
 * 
 * Класс валидатора
 * @author Anton Zavidov
 * @package myLiveShop
 */

/**
 * Класс валидатора
 *
 */
class Validator extends Base {
		/**
	 * Тип поля универсальное
	 *
	 */
	const TYPE_CUSTOMIZED='customized';
	/**
	 * Поле содержит число
	 *
	 */
	const VALIDATE_INT='int';
	/**
	 * Поле содержит дату
	 *
	 */
	const VALIDATE_DATE='date';
	/**
	 * Поле содержит дату и время
	 *
	 */
	const VALIDATE_DATETIME='datetime';
	/**
	 * Поле содержит текст
	 *
	 */
	const VALIDATE_TEXT='text';
	/**
	 * Поле содержит email
	 *
	 */
	const VALIDATE_EMAIL='email';
	/**
	 * Поле содержит md5 хеш
	 *
	 */
	const VALIDATE_HASH='hash';
	/**
	 * Поле содержит значение 0 или 1
	 *
	 */
	const VALIDATE_BOOL='bool';
	/**
	 * Поле содержит url
	 *
	 */
	const VALIDATE_URL='url';
	/**
	 * Поле содержит html
	 *
	 */
	const VALIDATE_HTML='html';
	/**
	 * Поле содержит различные данные
	 *
	 */
	const VALIDATE_CUSTOM='custom';
	/**
	 * Соответствия типов и валидаторов
	 *
	 * @var array
	 */
	private static $validate_type=array(
		Field::TYPE_INT => array(
			self::VALIDATE_INT,
			self::VALIDATE_BOOL,
			self::VALIDATE_CUSTOM),
		Field::TYPE_DATE => array(
			self::VALIDATE_DATE,
			self::VALIDATE_CUSTOM),
		Field::TYPE_DATETIME => array(
			self::VALIDATE_DATETIME,
			self::VALIDATE_CUSTOM),
		Field::TYPE_STRING =>array(
			self::VALIDATE_TEXT,
			self::VALIDATE_HASH,
			self::VALIDATE_DATE,
			self::VALIDATE_DATETIME,
			self::VALIDATE_EMAIL,
			self::VALIDATE_HTML,
			self::VALIDATE_INT,
			self::VALIDATE_URL,
			self::VALIDATE_CUSTOM),
		Field::TYPE_TEXT =>array(
			self::VALIDATE_TEXT,
			self::VALIDATE_DATE,
			self::VALIDATE_HASH,
			self::VALIDATE_DATETIME,
			self::VALIDATE_EMAIL,
			self::VALIDATE_HTML,
			self::VALIDATE_INT,
			self::VALIDATE_URL,
			self::VALIDATE_CUSTOM),
		Field::TYPE_CUSTOMIZED =>array(
			self::VALIDATE_CUSTOM,
			self::VALIDATE_TEXT,
			self::VALIDATE_BOOL,
			self::VALIDATE_HASH,
			self::VALIDATE_DATE,
			self::VALIDATE_DATETIME,
			self::VALIDATE_EMAIL,
			self::VALIDATE_HTML,
			self::VALIDATE_INT,
			self::VALIDATE_URL)
		);
	/**
	 * Конструктор
	 *
	 */
	public function __construct(){	
		parent::__construct(__CLASS__);
	}
	/**
	 * Проверка соответствия типов валидаторов
	 *
	 * @param Field $field ссылка на поле
	 */
	public static function typeTest(Field &$field){
		if(isset(self::$validate_type[$field->_('type')])){
			if(!in_array($field->_('validate_type'),self::$validate_type[$field->_('type')])){
				new CoreExeption('Попытка указать валидатор '.$field->_('validate_type').' не соответствующий полю с типом '.$field->_('type').'. Тип валидации изменён на '.self::$validate_type[$field->_('type')][0],E_NOTICE,__FILE__,__LINE__,array('field'=>$field->fields));
				$field->validate_type=self::$validate_type[$field->_('type')][0];
			}elseif ($field->_('validate_type')==self::VALIDATE_CUSTOM && !is_array($field->_('validate_type'),callback)){
				new CoreExeption('Не указанна callback функция для валидатора типа '.$field->_('validate_type').'. Тип валидации изменён на '.self::VALIDATE_TEXT ,E_NOTICE,__FILE__,__LINE__,array('field'=>$field->fields));
				$field->validate_type=self::$validate_type[$field->_('type')][0];
			}
		}else{
			new CoreExeption('Указан неизвестный валидатор '.$field->_('validate_type').'. Тип валидации изменён на '.self::VALIDATE_CUSTOM ,E_NOTICE,__FILE__,__LINE__,array('field'=>$field->fields));
			$field->validate_type=self::VALIDATE_CUSTOM;
		}
	}
	/**
	 * базовая универсальная функция
	 *
	 * @param mixed $value ссылка на переменную
	 * @param Field $field ссылка на поле
	 * @return mixed true или текст ошибки
	 */
	public static function _(&$value, Field &$field){
		$type='validateAs'.ucfirst($field->_('validate_type'));
		//немножко магии ^_^
		if(method_exists(__CLASS__,$type)){
			return self::$type($value,$field);
		}else{
			new CoreExeption('Не удалось произвести валидацию поля '.$field->_('name').', так как указан неизвестный тип валидации '.$field->_('validate_type'),E_WARNING,__FILE__,__LINE__,array('value'=>$value));
			return 'Ошибка валидации';
		}
	}
	/**
	 * валидатор по умолчанию для определённого типа поля
	 *
	 * @param string $type тип поляs
	 * @return string true тип валитатора
	 */
	public static function defaultValidator($type){
		return self::$validate_type[$type][0];
	}
	/**
	 * Валидация чисел
	 *
	 * @param mixed $value ссылка на переменную
	 * @param Field $field ссылка на поле
	 * @return mixed true или текст ошибки
	 */
	public static function validateAsInt(&$value, Field &$field){
		if(!is_numeric($value))return 'Значение должно быть числовым';
		$lenght=$field->_('lenght');
		if($value>pow(10,$lenght))return 'Значение не должно превышать '.pow(10,$lenght);
		return true;
	}
	/**
	 * Валидация бинарного значения
	 *
	 * @param mixed $value ссылка на переменную
	 * @param Field $field ссылка на поле
	 * @return mixed true или текст ошибки
	 */
	public static function validateAsBool(&$value, Field &$field){
		if(!is_numeric($value))return 'Значение должно быть числовым';
		if($value!=1 && $value!=0)return 'Значение должно быть 1 или 0';
		return true;
	}
	/**
	 * Валидация строк
	 *
	 * @param mixed $value ссылка на переменную
	 * @param Field $field ссылка на поле
	 * @return mixed true или текст ошибки
	 */
	public static function validateAsText(&$value, Field &$field){
		if(!is_numeric($value) && !is_string($value))return 'Значение должно быть числовым либо строковым';
		$lenght=$field->_('lenght');
		if($lenght && mb_strlen($value,'UTF-8')>$lenght){
		    return 'Длинна строки не должна превышать '.$lenght.' символов';
		}
		return true;
	}
	/**
	 * Валидация email
	 *
	 * @param mixed $value ссылка на переменную
	 * @param Field $field ссылка на поле
	 * @return mixed true или текст ошибки
	 */
	public static function validateAsEmail(&$value, Field &$field){
		if(!is_string($value))return 'Значение должно быть строкой';
		if(!preg_match("/[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})/i", $value))return 'Значение должно быть email';
		$lenght=$field->_('lenght');
		if(strlen($value)>$lenght)return 'Длинна строки не должна превышать '.$lenght.' символов';
		return true;
	}
	/**
	 * Валидация haxh
	 *
	 * @param mixed $value ссылка на переменную
	 * @param Field $field ссылка на поле
	 * @return mixed true или текст ошибки
	 */
	public static function validateAsHash(&$value, Field &$field){
		if(!is_numeric($value) && !is_string($value))return 'Значение не верно';
		if (preg_match('/[^0-9a-f]/i', $value))return 'Значение не верно';
		$lenght=$field->_('lenght');
		if(mb_strlen($value)>$lenght)return 'Длинна строки не должна превышать '.$lenght.' символов';
		return true;
	}
	/**
	 * Валидация date
	 *
	 * @param mixed $value ссылка на переменную
	 * @param Field $field ссылка на поле
	 * @return mixed true или текст ошибки
	 */
	public static function validateAsDate(&$value, Field &$field){
		if(!strtotime($value))return 'Значение должно быть датой';
		return true;
	}
	/**
	 * Валидация date time
	 *
	 * @param mixed $value ссылка на переменную
	 * @param Field $field ссылка на поле
	 * @return mixed true или текст ошибки
	 */
	public static function validateAsDatetime(&$value, Field &$field){
		if(!strtotime($value))return 'Значение должно быть датой';
		return true;
	}
	/**
	 * Валидация кастомайзных полей
	 *
	 * @param mixed $value ссылка на переменную
	 * @param Field $field ссылка на поле
	 * @return mixed true или текст ошибки
	 */
	public static function validateAsCustom(&$value, Field &$field){
		$callback=$field->_('validate_callback');
		if(!is_array($callback)){
			new CoreExeption('Не указанна callback функция для валидатора типа '.$field->_('validate_type').'. Тип валидации изменён на '.self::VALIDATE_TEXT ,E_WARNING,__FILE__,__LINE__,array('field'=>$field->_('fields'),'value'=>$value));
			return 'Ошибка валидации';
		}
		$className=$callback[0];
		$methodName=$callback[1];
		if(!method_exists($className,$methodName)){
			new CoreExeption('Не удалось произвести валидацию поля '.$field->_('name').', так как не удалось вызвать функцию '.$className.'->'.$methodName.'(value)',E_WARNING,__FILE__,__LINE__,array('field'=>$field->_('fields'),'value'=>$value));
			return 'Ошибка валидации';
		}
		return $className->$methodName($value);
	}
}